/**
 * 作者：gwzh
 * 日期：2018/2/7
 * 说明：业务工具包，所以子页面的业务公共方法
 * 版本：2.0.0
 * http://fly.layui.com/jie/17493/
 *
 * 日志：
 *   v1.0.0 2018/2/7 新建组件
 *   v1.1.0 2018/4/* 添加新的功能-设置默认值
 *   v1.1.1 2018/5/4 默认值bug修复，添加参数配置
 *   v1.1.2 2018/5/16 添加回调参数，添加不可选择效果
 *   v1.1.3 2018/10/16-2018/10/18 处理新的接口问题
 *   v1.1.4 2019/03/31
 *     增加了 ajax.method 控制
 *     增加了 属性的控制
 *   v1.2.0 2019/4/8 重构
 *   v2.0.0 2019/12/11 最低兼容 layui 2.5.0 以上版本
 */

layui.define(['jquery', 'tree'], function(exports) {
  var $ = layui.jquery;

  var HIDE = 'layui-hide';
  var CLASS = 'layui-form-select';
  var TITLE = 'layui-select-title';

  var $window = $(window);
  var $document = $(document);

  var TreeSelect = function(options) {
    this.v = '1.2.0';
    this.options = null;
    this._data(options); // 处理参数
  };

  TreeSelect.prototype._data = function(options) {
    var $el = options.$el;

    var attrDisabled = $el.attr('disabled'); // 2018/5/16
    var attrPlaceholder = $el.attr('placeholder'); // 2019/4/8
    var attrLayIgnore = $el.attr('lay-ignore');

    var placeholder = attrPlaceholder || options.placeholder;
    var disabled = attrDisabled ? true : !!options.disabled;
    var value = $el.val() || options.defaultValue || '';
    var hasValue = !!options.hasDefaultValue;
    var treeData = $.isArray(options.data) ? options.data : [options.data];
    var renderId = 'treeselect-' + new Date().getTime();
    var $render = $([
      '<div class="layui-unselect ' + CLASS + '">',
      '  <div class="' + TITLE + '">',
      '    <input type="text" class="layui-input layui-input-small layui-unselect" placeholder="' + placeholder + '" readonly>',
      '    <i class="layui-edge"></i>',
      '  </div>',
      '  <div id="' + renderId + '" class="layui-anim layui-anim-upbit layui-form-select-menu"></div>',
      '</div>'
    ].join(''));

    if (disabled) {
      $render.addClass('layui-select-disabled');
      $render.find('input').addClass('layui-disabled');
    }

    if (hasValue) {
      $render.find('input').val(value);
    }

    // 更新 options
    options.defaultValue = value;
    options.hasDefaultValue = hasValue;
    options.data = treeData;
    options.disabled = disabled;
    options.placeholder = placeholder;
    options.layIgnore = attrLayIgnore;
    options.renderId = renderId;
    options.$render = $render;

    this.options = options;
  };

  TreeSelect.prototype._getDefaultText = function(targetId) {
    var options = this.options;

    var data = options.data;
    var textKey = options.textKey;
    var valueKey = options.valueKey;

    if (!targetId) return data[0][textKey] || '';

    var ret = '';
    var fn = function(data, id) {
      for (var i = 0, len = data.length; i < len; i++) {
        var item = data[i];
        if (!item[valueKey] || !item[textKey]) throw new Error('错误的treeselect数据, 请参考layui.tree拼接数据');

        if (item[valueKey] === id) {
          ret = item[textKey] || '';
        } else {
          if (item.children && item.children.length) {
            fn(item.children, id);
          }
        }
      }
    };
    fn(data, targetId);

    return ret;
  };

  TreeSelect.prototype.render = function(cb) {
    var options = this.options;
    var $el = options.$el;
    var $render = options.$render;
    var renderId = options.renderId;
    var layIgnore = options.layIgnore;
    var disabled = options.disabled;
    var textKey = options.textKey;
    var valueKey = options.valueKey;
    var treeCallback = options.click;
    var treeData = options.data;
    var value = options.defaultValue;
    var hasValue = options.hasDefaultValue;

    var events = function() {
      var $title = $render.find('.' + TITLE);
      var $input = $title.find('input');
      var $tree = $render.find('.layui-tree');

      var defaultItem = treeData[0] || {};
      var defaultText; var defaultValue;

      // 判断是否需要设置初始值
      if (hasValue) {
        if (value) {
          defaultText = this._getDefaultText(value);
          defaultValue = value;
        } else {
          defaultText = defaultItem[textKey] || '';
          defaultValue = defaultItem[valueKey] || '';
        }
        $el.val(defaultValue);
        $input.val(defaultText);
      }

      if (disabled) return;

      var hide = function(e, clear) {
        var $this = $(e.target);

        if (!$this.parent().hasClass(TITLE) || clear) {
          $('.' + CLASS).removeClass(CLASS + 'ed ' + CLASS + 'up');
        }
      };

      var showDown = function() {
        // dl.css('top', '') // hezl 将top 复位
        var top = $render.offset().top + $render.outerHeight() + 5 - $window.scrollTop();
        var dlHeight = $tree.outerHeight();

        $render.addClass(CLASS + 'ed');

        if (top + dlHeight > $window.height() && top >= dlHeight) {
          $render.addClass(CLASS + 'up');
        }
        /* else {
                   // hezl 20181022 定位重写定义
                   var ANIM_UP = 30, SPACE = 5; // 动画需要的距离和弹窗的间隔
                   var reElemBottom = reElem.get(0).getBoundingClientRect().bottom;
                   var dlTop = parseInt(dl.css('top'));
                   var winHeight = $window.height();
                   if (reElemBottom + dlHeight + ANIM_UP > winHeight ) {
                     var computeValue = dlTop - (reElemBottom + SPACE - (winHeight - dlHeight - ANIM_UP))
                     dl.css('top', computeValue)
                   }
                 }*/
      };

      var hideDown = function() {
        $render.removeClass(CLASS + 'ed ' + CLASS + 'up');
        $input.blur();
      };

      $title.on('click', function(e) {
        if ($render.hasClass(CLASS + 'ed')) {
          hideDown();
        } else {
          hide(e, true);
          showDown();
        }
        $tree.find('.layui-select-none').remove();
      });

      // 点击箭头获取焦点
      $title.find('.layui-edge').on('click', function() {
        $input.focus();
      });

      // 键盘事件
      $input.on('keyup', function(e) {
        e.keyCode === 9 && showDown(); // Tab键
      }).on('keydown', function(e) {
        var keyCode = e.keyCode;

        if (keyCode === 9) { // Tab键
          hideDown();
        } else if (keyCode === 13) { // 回车键
          e.preventDefault();
        }
      });

      // 渲染tree
      layui.tree.render({
        elem     : '#' + renderId,
        data     : treeData,
        accordion: true,
        click    : function(node) {
          var ret; var data = node.data;

          $.isFunction(treeCallback) && (ret = treeCallback(data));
          if ($.type(ret) === 'undefined' || ret) {
            $el.val(data[valueKey]).removeClass('layui-form-danger');
            $input.val(data[textKey]);
            hideDown();
          }
          return false;
        }
      });

      $.isFunction(cb) && cb();

      // 点击树箭头不隐藏
      $render.find('.layui-form-select-menu').on('click', function() {
        return false;
      });
      // 关闭下拉
      $document.off('click', hide).on('click', hide);
    };

    if (typeof layIgnore === 'string') {
      $el.removeClass(HIDE);
      $el.removeAttr('hidden');
      $el[0].tagName.toLowerCase === 'input' && $el.attr('type', 'text');
      return $el;
    }
    $el.addClass(HIDE);

    var hasRender = $el.next('.' + CLASS);
    hasRender[0] && hasRender.remove();
    $el.after($render);

    events.call(this);
  };

  exports('treeselect', function(options, cb) {
    var defaults = {
      elem           : null,
      data           : [], // data 可指定为数据或者是一个链接地址来返回数据，数据格式参考 layui.tree
      textKey        : 'name',
      valueKey       : 'id',
      placeholder    : '请选择',
      defaultValue   : '',
      hasDefaultValue: true,
      disabled       : false,
      click          : $.noop,
      // $.ajax()
      url            : '',
      param          : {}, // $.ajax({ data: param })
      method         : 'POST', // $.ajax({ type: method })
      async          : true
    };

    options = $.type(options) === 'object' ? $.extend({}, defaults, options) : {};
    options.$el = $(options.elem);
    if (!options.$el[0]) return; // 无选择器则返回

    var type = $.type(options.data);
    if (type === 'string') {
      try {
        options.data = JSON.parse(options.data);
        new TreeSelect(options).render(cb);
        return;
      } catch (e) {
        //
      }

      options.url = options.data;
      options.data = [];
      $.ajax({
        url     : options.url,
        data    : options.param,
        type    : options.method,
        async   : options.async,
        dataType: 'json',
        timeout : 15 * 1000,
        success : function(response) {
          var resType = $.type(response);

          if (resType === 'string') {
            try {
              options.data = response && JSON.parse(response);
            } catch (e) {
              //
            }
          } else if (response) {
            options.data = response;
          }

          new TreeSelect(options).render(cb);
        }
      });
    } else {
      new TreeSelect(options).render(cb);
    }
  });
});
